/*
 * get_dev_name.cpp
 */

/*
 * Copyright (c) 2010-2011 Masoom Shaikh<masoom.shaikh@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
*/

#include <iostream>
#include <errno.h>
#include <string.h>
#include <bluetooth.h>

/*
 * removes duplicate entries from result and returns the new size
 * free()'s the original array, result is calloc()ed
 * TODO: implement in a better way
 */
int do_uniq( const int size, struct bt_devinquiry** p_result)
{
    struct bt_devinquiry* old_result = *p_result;
    struct bt_devinquiry* new_result = new struct bt_devinquiry[size];
    memset( new_result, 0, sizeof(struct bt_devinquiry) * size);

    int count = 0;
    for ( int i = 0; i < size; ++i)
    {
        int j;
        for ( j = 0; j < count; ++j)
        {
            if ( bdaddr_same( &( new_result[j].bdaddr), &( old_result[i].bdaddr)))
                break;
        }

        if ( j == count)
            new_result[count++] = old_result[i];
    }

    free(old_result);
    *p_result = new_result;
    return count;
}

int main( int argc, char* argv[])
{
    /* search devices */
    struct bt_devinquiry* result = 0;
    int num = bt_devinquiry( 0, 0, 0, &result);
    if ( num <= 0)
    {
        if ( h_errno)
            herror( "no devices found");
        else
            std::cout << "no devices found" << std::endl;
        return num;
    }

    /* remove duplicate entries */
    num = do_uniq( num, &result);
    std::cout << num << " device(s) found" << std::endl;

    /* try to query device's name */
    int s = bt_devopen( "ubt0hci");
    if ( s == -1)
    {
        if ( h_errno)
            herror( "bt_devopen error\n");
        else
            std::cout << "bt_devopen error" << std::endl;
        return -1;
    }

    for ( int i = 0; i < num; ++i)
    {
        struct bt_devreq request;
        memset( &request, 0, sizeof(request));
        request.opcode = NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_REMOTE_NAME_REQ);
        request.event = NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL;

        ng_hci_remote_name_req_cp cp;
        memset( &cp, 0, sizeof(cp));
        bdaddr_copy( &cp.bdaddr, &result[i].bdaddr);
        cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
        cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
        request.cparam = (void*)&cp;
        request.clen = sizeof(cp);

        ng_hci_remote_name_req_compl_ep ep;
        memset( &ep, 0, sizeof(ep));
        request.rparam = (void*)&ep;
        request.rlen = sizeof(ep);

        int status = bt_devreq( s, &request, 5);
        if ( status == 0)
        {
            std::cout << "status: " << ep.status << std::endl;
            std::cout << "name: " << ep.name << std::endl;
        }
        else if (status == -1)
        {
            if ( h_errno)
                herror( "bt_devreq error\n");
            else
                std::cout << "bt_devreq error" << std::endl;
        }
        else
        {
            std::cout << "bt_devreq unknown return value" << std::endl;
        }
    }
    bt_devclose(s);
    return 0;
}
